#pragma once
#include "buffer.hpp"
#include <initializer_list>

namespace opengl {

struct vertex_attribute {
public:
    vertex_attribute(){};
    vertex_attribute(u32 index, u32 type, i32 num_components, u32 offset, u32 binding_index = 0)
        : index(index), num_components(num_components), type(type), offset(offset), binding_index(binding_index) {}

public:
    u32 index = 0;
    u32 type = 0;
    i32 num_components = 0;
    u32 offset = 0;
    u32 binding_index = 0; // Binding index for the vertex buffer
};

class vertex_array {
public:
    using attribute_list = std::initializer_list<vertex_attribute>;

    /* Constructors */
    OPENGLAPI vertex_array(); // Declare a vertex array but do not create it.
    OPENGLAPI vertex_array(const vertex_array &) = delete;
    OPENGLAPI vertex_array(vertex_array &&other) noexcept;
    OPENGLAPI vertex_array(attribute_list attributes);
    OPENGLAPI void create(attribute_list attributes);
    /* Vertex attributes */
    OPENGLAPI void append_attribute(const vertex_attribute &attribute);
    OPENGLAPI void append_attribute(u32 index, u32 type, i32 num_components, u32 offset, u32 binding_index = 0);

    OPENGLAPI void bind() const;
    OPENGLAPI void set_vertex_buffer(const buffer &vertex_buffer, i32 stride, i32 offset = 0,
                                     u32 binding_index = 0) const;     // Bind a vertex buffer to this VAO with a
                                                                       // specific stride and offset
    OPENGLAPI void set_index_buffer(const buffer &index_buffer) const; // Bind an index buffer to this EBO

    /* Operators */
    OPENGLAPI vertex_array &operator=(const vertex_array &) = delete;
    OPENGLAPI vertex_array &operator=(vertex_array &&other);

    /* Destructor */
    OPENGLAPI ~vertex_array();

public:
public:
    u32 id;
};

} // namespace opengl